home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: KeyboardModule.c Contains: HID Module for USB Keyboard Version: xxx put version here xxx Copyright: © 1997-1999 by Apple Computer, Inc., all rights reserved. */ #include <Devices.h> #include <DriverServices.h> #include <Gestalt.h> #include <MacTypes.h> #include <Processes.h> #include <USB.h> #include "KeyboardModule.h" #include "PackageVersion.h" usbKeyboardPBStruct myKeyboardPB; usbKeyboardPBStruct shimKeyboardPB; void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock) { paramblock->usbReference = theInterfaceRef; paramblock->pbVersion = kUSBCurrentPBVersion; paramblock->usb.cntl.WIndex = 0; paramblock->usb.cntl.WValue = 0; paramblock->usbBuffer = nil; paramblock->usbActCount = 0; paramblock->usbReqCount = 0; paramblock->usbFlags = 0; paramblock->usbOther = 0; paramblock->usbStatus = noErr; } static Boolean immediateError(OSStatus err) { return((err != kUSBPending) && (err != noErr) ); } void KeyboardInitiateTransaction(USBPB *pb) { register usbKeyboardPBStruct *pKeyboardPB; OSStatus myErr; pKeyboardPB = (usbKeyboardPBStruct *)(pb); //USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": KeyboardInitiateTransaction PB", (long)pKeyboardPB); //USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": KeyboardInitiateTransaction ref", (long)pKeyboardPB->pb.usbRefcon); pKeyboardPB->transDepth++; if (pKeyboardPB->transDepth < 0) { USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": transDepth < 0 (initiation)", pKeyboardPB->transDepth); //USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth < 0 (initiation)", pKeyboardPB->pb.usbRefcon ); } if (pKeyboardPB->transDepth > 1) { USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": transDepth >1 (initiation)", pKeyboardPB->transDepth); return; // trying to reuse PB, bail out before we cause more problems. //USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth > 1 (initiation)", pKeyboardPB->pb.usbRefcon ); } if (pKeyboardPB->driverRemovalPending) { pKeyboardPB->pb.usbRefcon = kReturnFromDriver; return; } switch(pKeyboardPB->pb.usbRefcon & ~kRetryTransaction) { case kSetKeyboardLEDs: InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb); pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface); pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetReport; pKeyboardPB->pb.usb.cntl.WValue = (kHIDRtOutputReport << 8); pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber; pKeyboardPB->pb.usbBuffer = (Ptr)&pKeyboardPB->hidReport[0]; pKeyboardPB->pb.usbReqCount = 1; pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pKeyboardPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kSetKeyboardLEDs - immediate error", myErr); } break; case kConfigureInterface: InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb); pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBConfigureInterface( &pKeyboardPB->pb ); if(immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kConfigureInterface - immediate error", myErr); pKeyboardPB->pb.usbRefcon = kReturnFromDriver; } break; case kSetProtocol: InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb); pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface); pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetProtocol; pKeyboardPB->pb.usb.cntl.WValue = kHIDBootProtocolValue; pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber; pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pKeyboardPB->pb); if (immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kSetProtocol - immediate error", myErr); } break; case kSetIdleRequest: USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Do a SetIdle on non-Apple keyboards, as some 3rd party keyboards don't send reports on key release", pKeyboardPB->pipeRef); InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb); pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface); pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetIdle; pKeyboardPB->pb.usb.cntl.WValue = ((24/4)<<8); // force a read completion if idle for more than 24ms pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber; pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(&pKeyboardPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kSetIdleRequest - immediate error", myErr); } break; case kFindPipe: InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb); pKeyboardPB->pb.usbFlags = kUSBIn; pKeyboardPB->pb.usbClassType = kUSBInterrupt; pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBFindNextPipe( &pKeyboardPB->pb ); if((immediateError(myErr)) || (pKeyboardPB->pb.usbBuffer == nil)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kFindPipe - immediate error", myErr); pKeyboardPB->pb.usbRefcon = kReturnFromDriver; } break; case kReadInterruptPipe: InitParamBlock(pKeyboardPB->pipeRef, &pKeyboardPB->pb); pKeyboardPB->pb.usbBuffer = (Ptr)pKeyboardPB->hidReport; pKeyboardPB->pb.usbReqCount = 0x08; pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber; pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; // Get USB Version to to see if we support the debug aware flag ( version > 1.4 ) if ( pKeyboardPB->usbVersion >= kUSBVersion14 ) { pKeyboardPB->pb.usbFlags |= kUSBDebugAwareFlag; } myErr = USBIntRead(&pKeyboardPB->pb); if(immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kReadInterruptPipe - immediate error", myErr); } break; case kClearFeature: USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Do a clear feature on the interrupt endpoint", pKeyboardPB->pipeRef); InitParamBlock(pKeyboardPB->pipeRef, &pKeyboardPB->pb); pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint); pKeyboardPB->pb.usb.cntl.BRequest = kUSBRqClearFeature; pKeyboardPB->pb.usb.cntl.WValue = kUSBFeatureEndpointStall; pKeyboardPB->pb.usbFlags = kUSBAddressRequest; /* kUSBAddressRequest asks the USL to do a translation of piperef to endpoint number */ pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBDeviceRequest(pb); if(immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->pb.usbReference, kUSBInternalErr, kKeyboardModuleName": kClearFeature - immediate error", myErr); } break; case kResetMouse: InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb); pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBResetDevice( &pKeyboardPB->pb ); if(myErr == kUSBDeviceBusy) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": reset busy, backing off", myErr); pKeyboardPB->pb.usbReqCount = 100; pKeyboardPB->pb.usbRefcon = kResetMouseDelay | kCompletionPending; pKeyboardPB->pb.usbFlags = kUSBReturnOnException; USBDelay( &pKeyboardPB->pb ); } else if(immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kResetMouse - immediate error", myErr); pKeyboardPB->pb.usbRefcon = kReturnFromDriver; } break; case kGetPortStatus: InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb); pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc; pKeyboardPB->pb.usbRefcon |= kCompletionPending; myErr = USBPortStatus( &pKeyboardPB->pb ); if(myErr == kUSBDeviceBusy) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": status busy, backing off", myErr); pKeyboardPB->pb.usbReqCount = 100; pKeyboardPB->pb.usbRefcon = kPortStatusDelay | kCompletionPending; pKeyboardPB->pb.usbFlags = kUSBReturnOnException; USBDelay( &pKeyboardPB->pb ); } else if(immediateError(myErr)) { USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kGetPortStatus - immediate error", myErr); pKeyboardPB->pb.usbRefcon = kReturnFromDriver; } break; default: USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName" - Transaction completed with bad refcon value", pKeyboardPB->pb.usbRefcon ); pKeyboardPB->pb.usbRefcon = kUndefined + kReturnFromDriver; break; } // At this point the control is returned to the system. If a USB transaction // has been initiated, then it will call the Completion proc // (below) to handle the results of the transaction. } void KeyboardCompletionProc(USBPB *pb) { unsigned char * errstring; register usbKeyboardPBStruct *pKeyboardPB; USBPipeState pipeState; pKeyboardPB = (usbKeyboardPBStruct *)(pb); //USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": KeyboardCompletionProc PB", (long)pKeyboardPB); //USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": KeyboardCompletionProc ref", (long)pKeyboardPB->pb.usbRefcon); pKeyboardPB->transDepth--; if (pKeyboardPB->transDepth < 0) { //USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth < 0 (completion)", pKeyboardPB->pb.usbRefcon ); USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": transDepth <0 (completion) exiting", pKeyboardPB->transDepth); return; // pb being reused, bail before we cause more damage } if (pKeyboardPB->transDepth > 1) { USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": transDepth >1 (completion)", pKeyboardPB->transDepth); //USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth > 1 (completion)", pKeyboardPB->pb.usbRefcon ); } if( (pKeyboardPB->pb.usbStatus != noErr) && ((pKeyboardPB->pb.usbRefcon & kStageMask) != kGetPortStatus) ) // was there an error? { switch(pKeyboardPB->pb.usbRefcon & 0x0fff) // yes, so show where the error occurred { case kSetKeyboardLEDs: errstring = kKeyboardModuleName": Error during kSetKeyboardLEDs"; break; case kConfigureInterface: errstring = kKeyboardModuleName": Error during kConfigureInterface"; break; case kSetProtocol: errstring = kKeyboardModuleName": Error during kSetProtocol"; break; case kSetIdleRequest: errstring = kKeyboardModuleName": Error during kSetIdleRequest"; break; case kFindPipe: errstring = kKeyboardModuleName": Error during kFindPipe"; break; case kReadInterruptPipe: errstring = kKeyboardModuleName": Error during kReadInterruptPipe"; break; case kClearFeature: errstring = kKeyboardModuleName": Error during kClearFeature"; break; default: errstring = kKeyboardModuleName": Error occurred, but state is unknown"; break; }; USBExpertFatalError(pKeyboardPB->interfaceRef, pKeyboardPB->pb.usbStatus, errstring, (pKeyboardPB->pb.usbRefcon & 0x0fff)); pKeyboardPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); // set up to retry the transaction pKeyboardPB->pb.usbRefcon |= kRetryTransaction; pKeyboardPB->retryCount--; if ((!pKeyboardPB->retryCount) || (pKeyboardPB->pb.usbStatus == kUSBAbortedError)) // have we exhausted the retries? { // or received an abort? USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Pipe abort or unable to recover from error", pKeyboardPB->interfaceRef); pKeyboardPB->pb.usbRefcon = kReturnFromDriver; // if so, just exit. pKeyboardPB->intPipeAborted = true; } else // if it didn't abort and there's retries left, then... { if (pKeyboardPB->pipeRef) // check if the pipe is open. { USBGetPipeStatusByReference(pKeyboardPB->pipeRef, &pipeState); // yes, so what it's state? if (pipeState != kUSBActive) // if it's not active, try to clear it. It might be stalled... { USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Pipe is open and stalled, clearing stall...", pKeyboardPB->interfaceRef); USBClearPipeStallByReference(pKeyboardPB->pipeRef); } } if( (pKeyboardPB->pb.usbStatus == kUSBNotRespondingErr) ) { USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": doing port status", pKeyboardPB->interfaceRef); pKeyboardPB->previousState = pKeyboardPB->pb.usbRefcon; pKeyboardPB->pb.usbRefcon = kGetPortStatus; } } } else { pKeyboardPB->pb.usbRefcon &= ~kRetryTransaction; pKeyboardPB->retryCount = kKeyboardRetryCount; } if (pKeyboardPB->pb.usbRefcon & kCompletionPending) { pKeyboardPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver); switch(pKeyboardPB->pb.usbRefcon) { case kSetKeyboardLEDs: pKeyboardPB->pb.usbRefcon = kReturnFromDriver; pKeyboardPB->keyboardReady = true; break; case kConfigureInterface: pKeyboardPB->pb.usbRefcon = kSetProtocol; break; case kSetProtocol: if (kVendorID_AppleComputer == USBToHostWord(pKeyboardPB->deviceDescriptor.vendor)) { pKeyboardPB->pb.usbRefcon = kFindPipe; } else { pKeyboardPB->pb.usbRefcon = kSetIdleRequest; } break; case kSetIdleRequest: pKeyboardPB->pb.usbRefcon = kFindPipe; break; case kFindPipe: pKeyboardPB->pipeRef = pKeyboardPB->pb.usbReference; pKeyboardPB->pb.usbRefcon = kReadInterruptPipe; pKeyboardPB->keyboardReady = true; shimKeyboardPB.keyboardReady = true; break; case kReadInterruptPipe: NotifyRegisteredHIDUser(pKeyboardPB->hidDeviceType, pKeyboardPB->hidReport); pKeyboardPB->pb.usbRefcon = kReadInterruptPipe; break; case kClearFeature: pKeyboardPB->pb.usbRefcon = kReadInterruptPipe; break; case kPortStatusDelay: USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": kPortStatusDelay", pKeyboardPB->interfaceRef); pKeyboardPB->pb.usbRefcon = kGetPortStatus; break; case kResetMouseDelay: USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": kPortStatusDelay", pKeyboardPB->interfaceRef); pKeyboardPB->pb.usbRefcon = kResetMouse; break; case kResetMouse: USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": mouse now reset", pKeyboardPB->interfaceRef); // Just give up here, the composite driver should now take care of things. break; case kGetPortStatus: if(pb->usbStatus == kUSBDeviceDisconnected) { USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": port status gives device disconnected, exiting", pKeyboardPB->interfaceRef); pKeyboardPB->pb.usbRefcon = kReturnFromDriver; // if so, just exit. } else if(pb->usbStatus == kUSBPortDisabled) { USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": port status gives port disabled, resetting", pKeyboardPB->interfaceRef); pKeyboardPB->pb.usbRefcon = kResetMouse; } else if(pb->usbStatus == noErr) { USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": port status transient error, restarting", pKeyboardPB->interfaceRef); //pKeyboardPB->retryCount = kMouseRetryCount; --> done automatically pKeyboardPB->pb.usbRefcon = pKeyboardPB->previousState; } else { USBExpertStatusLevel(1, pKeyboardPB->interfaceRef, kKeyboardModuleName": port status unknown error", pb->usbStatus); } break; default: USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName" - Transaction completed with bad refcon value", pKeyboardPB->pb.usbRefcon ); pKeyboardPB->pb.usbRefcon = kUndefined + kReturnFromDriver; break; } } if (!(pKeyboardPB->pb.usbRefcon & kReturnFromDriver) && (!pKeyboardPB->driverRemovalPending)) KeyboardInitiateTransaction(pb); } void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef) { #pragma unused (interfacenum) static Boolean beenThereDoneThat = false; if(beenThereDoneThat) { USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kKeyboardModuleName" is not reentrant", 12); return; } beenThereDoneThat = true; //DebugStr("\pIn Keyboard Module Interface entry routine"); shimKeyboardPB.driverRemovalPending = false; shimKeyboardPB.deviceDescriptor = *pDeviceDescriptor; shimKeyboardPB.interfaceDescriptor = *pInterfaceDescriptor; shimKeyboardPB.transDepth = 0; shimKeyboardPB.retryCount = kKeyboardRetryCount; shimKeyboardPB.pSHIMInterruptRoutine = nil; shimKeyboardPB.pSavedInterruptRoutine = nil; shimKeyboardPB.interfaceRef = theInterfaceRef; shimKeyboardPB.pipeRef = 0; shimKeyboardPB.keyboardReady = false; shimKeyboardPB.intPipeAborted = false; InitParamBlock(theInterfaceRef, &shimKeyboardPB.pb); shimKeyboardPB.pb.pbLength = sizeof(usbKeyboardPBStruct); shimKeyboardPB.pb.usbRefcon = 0; myKeyboardPB.driverRemovalPending = false; myKeyboardPB.deviceDescriptor = *pDeviceDescriptor; myKeyboardPB.interfaceDescriptor = *pInterfaceDescriptor; myKeyboardPB.transDepth = 0; myKeyboardPB.retryCount = kKeyboardRetryCount; myKeyboardPB.pSHIMInterruptRoutine = nil; myKeyboardPB.pSavedInterruptRoutine = nil; myKeyboardPB.interfaceRef = theInterfaceRef; myKeyboardPB.pipeRef = 0; myKeyboardPB.keyboardReady = false; myKeyboardPB.intPipeAborted = false; myKeyboardPB.sendRawReportFlag = false; myKeyboardPB.hidEmulationInit = false; InitParamBlock(theInterfaceRef, &myKeyboardPB.pb); myKeyboardPB.pb.pbLength = sizeof(usbKeyboardPBStruct); myKeyboardPB.pb.usbRefcon = kConfigureInterface; myKeyboardPB.usbVersion = 0; (void) Gestalt(gestaltUSBVersion,&myKeyboardPB.usbVersion); USBHIDControlDevice(kHIDEnableDemoMode,0); USBExpertStatusLevel(4, myKeyboardPB.interfaceRef, kKeyboardModuleName": starting up", 0); KeyboardInitiateTransaction(&myKeyboardPB.pb); }